package com.yuntsg.ruiijn.controller.search;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.IdUtil;
import com.yuntsg.nnsfcp.common.utils.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SimpleQuery;
import com.yuntsg.nnsfcp.common.utils.UserUtil;
import com.yuntsg.ruiijn.databse_search.entity.FileDetails;
import com.yuntsg.ruiijn.databse_search.entity.FileRecord;
import com.yuntsg.ruiijn.databse_search.entity.FolderType;
import com.yuntsg.ruiijn.databse_search.entity.SearchRecord;
import com.yuntsg.ruiijn.databse_search.service.*;
import common.bean.R;
import common.bean.RRException;
import common.util.*;
import common.vo.ContentsComparisonRes;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

@Controller
@RequestMapping("manager/pic/folder")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@SuppressWarnings("all")
@Slf4j
public class FolderTypeController {


    private final FolderTypeService folderTypeService;

    private final BussService bussService;

    @Resource
    UserUtil userUtil;

    private final CutImageUtil cutImageUtil;
    private final SearchSelfService searchSelfService;

    private final FileDetailService fileDetailService;

    private final FileRecordsService fileRecordsService;

    private final ImageComparison imageComparison;


    private final SearchRecordService searchRecordService;


    private final RedisUtil redisUtil;

    private final MinioUtil minioUtil;


    private final ExtractUtil extractUtil;

    private final CentralRequestUtil requestUtil;

    private final FeatureService featureService;

    public static InputStream bufferedImageToInputStream(BufferedImage bufferedImage) throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", os);
        return new ByteArrayInputStream(os.toByteArray());
    }

    /**
     * 文件夹列表
     *
     * @param vo
     * @return
     */
    @GetMapping("/folderlist")
    @ResponseBody
    public R folderlist(@RequestParam("rid") Integer rid, @RequestParam("type") Integer type) {
        if (type == 0) {
            List<FolderType> list = folderTypeService.list(Wrappers.<FolderType>lambdaQuery().select(FolderType::getId, FolderType::getFolderName, FolderType::getUId, FolderType::getRId, FolderType::getType).eq(FolderType::getUId, userUtil.getUid()).eq(FolderType::getType, 0).eq(FolderType::getRId, rid));
            list.add(new FolderType().setId(-1).setFolderName("论文图片").setUId(userUtil.getUid()).setType(0).setUId(userUtil.getUid()).setRId(rid));
            list.stream().forEach(folderType -> {
                folderType.setNum(fileDetailService.count(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getCollectionStatus, folderType.getId()).eq(FileDetails::getRid, rid)));
            });
            return R.ok().put("data", list);
        } else {
            List<FolderType> list = folderTypeService.list(Wrappers.<FolderType>lambdaQuery().eq(FolderType::getUId, userUtil.getUid()).select(FolderType::getId, FolderType::getFolderName, FolderType::getUId, FolderType::getRId, FolderType::getType).eq(FolderType::getType, 1).eq(FolderType::getRId, rid));
            if (list.size() == 0) {
                return R.error("暂无目录");
            }
            list.stream().forEach(folderType -> {
                folderType.setNum(Optional.ofNullable(folderType.getListId()).orElse(new ArrayList<>()).size());
            });
            return R.ok().put("data", list);
        }

    }

    /**
     * 文件列表
     *
     * @param vo
     * @return
     */
    @GetMapping("/filelist")
    @ResponseBody
    public R filelist(@RequestParam("id") Integer id, @RequestParam("rid") Integer rid) {
        FolderType folderType = new FolderType();
        if (id == -1) {
            folderType.setType(0).setId(id);
        } else {
            folderType = folderTypeService.getById(id);
        }
        if (folderType.getType() == 0) {
            return R.ok().put("data", fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getCollectionStatus, id).eq(FileDetails::getRid, rid)));
        } else {
            if (null == folderType.getListId() || folderType.getListId().size() > 0) {
                return R.ok().put("data", fileDetailService.listByIds(folderType.getListId())).put("mian", fileDetailService.getById(folderType.getMainId()));
            }
            return R.error("无内容");
        }

    }

    /**
     * 更新文件夹
     */
    @PostMapping("/folderupdate")
    @ResponseBody
    public R folderupdate(@RequestBody FolderType folderType) {
        if (null == folderType.getId()) {
            if (folderTypeService.count(Wrappers.<FolderType>lambdaQuery().eq(FolderType::getFolderName, folderType.getFolderName()).eq(FolderType::getType, 0).eq(FolderType::getRId, folderType.getRId()).eq(FolderType::getUId, userUtil.getUid())) > 0) {
                return R.error("文件夹名已存在");
            }
        } else {
            if (folderTypeService.count(Wrappers.<FolderType>lambdaQuery().eq(FolderType::getFolderName, folderType.getFolderName()).ne(FolderType::getId, folderType.getId()).eq(FolderType::getUId, userUtil.getUid()).eq(FolderType::getType, 0).eq(FolderType::getRId, folderType.getRId())) > 0) {
                return R.error("文件夹名已存在");
            }
        }
        folderTypeService.saveOrUpdate(folderType.setUId(userUtil.getUid()).setType(0).setRId(folderType.getRId()));
        return R.ok();
    }

    /**
     * 删除文件夹
     */
    @GetMapping("/folderdelete")
    @ResponseBody
    public R folderdelete(@RequestParam("id") Integer id) {
        if (fileDetailService.count(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getCollectionStatus, id)) > 0) {
            return R.error("该文件夹下有文件，不能删除");
        }
        return R.ok().put("data", folderTypeService.removeById(id));
    }

    /**
     * 文件转移
     */
    @GetMapping("/foldermove")
    @ResponseBody
    public R folderdelete(@RequestParam(value = "ids[]") String[] ids, @RequestParam("folderId") Integer folderId) {
        return R.ok().put("data", fileDetailService.saveOrUpdateBatch(fileDetailService.listByIds(Arrays.asList(ids)).stream().map(s -> s.setCollectionStatus(folderId)).collect(Collectors.toList())));
    }

    /**
     * 颜色反转
     */
    @GetMapping("/colorInversion")
    @ResponseBody
    public R colorInversion(@RequestParam(value = "ids[]") String[] ids) {
        fileDetailService.listByIds(Arrays.asList(ids)).stream().forEach(f -> {
            cutImageUtil.colorInversion(f.getPath());
            Map<Integer, String> map = SimpleQuery.map(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, f.getId()).ne(FileDetails::getFId, f.getId()), FileDetails::getId, FileDetails::getPath);
            fileDetailService.removeByIds(map.keySet());
            map.values().stream().forEach(url -> minioUtil.remove(url));
            List<FileDetails> list = cutImageUtil.workNoUid(f.getPath(), f.getId(), f.getRid(), -1, userUtil.getUid());
        });
        return R.ok();
    }

    /**
     * 目录对比
     */
    @RequestMapping("contentsComparison")
    @ResponseBody
    public R contentsComparison(@RequestParam("orginId") Integer orginId, @RequestParam("targetId") Integer targetId, @RequestParam("rid") Integer rid, @RequestParam("parts") Integer parts, @RequestParam("direction") Integer direction) throws IOException {
        String uid = userUtil.getUidStr();

//        if (!redisUtil.canWork(uid)) {
//            return R.error("应用队列已满，请稍后重试");
//        }
        List<FileDetails> orginList = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getCollectionStatus, orginId));
        List<FileDetails> targetList = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getCollectionStatus, targetId));
        if (orginList.size() == 0 || targetList.size() == 0) {
            return R.error("目录下没有文件");
        }
        String contentsComparisonKey = IdUtil.fastSimpleUUID();
        new Thread(() -> {
            fileDetailService.contentsComparisonStep(orginId, targetId, orginList, targetList, uid, parts, direction, contentsComparisonKey);
        }).start();

        return R.ok().put("contentsComparisonKey", contentsComparisonKey);
    }

    /**
     * 连线对比
     */
    @RequestMapping("contentsComparison_line")
    @ResponseBody
    public R contentsComparisonLine(@RequestParam("orginId") Integer orginId, @RequestParam("targetId") Integer targetId, @RequestParam("rid") Integer rid, @RequestParam("level") Integer level) throws IOException {
        String uid = userUtil.getUidStr();
//        if (!redisUtil.canWork(uid)) {
//            return R.error("应用队列已满，请稍后重试");
//        }
        List<FileDetails> orginList = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getCollectionStatus, orginId));
        List<FileDetails> targetList = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getCollectionStatus, targetId));

        if (orginList.size() == 0 || targetList.size() == 0) {
            return R.error("目录下没有文件");
        }
        String contentsComparisonKey = IdUtil.fastSimpleUUID();


        int flag = orginList.size() * targetList.size();

        new Thread(() -> {
            fileDetailService.contentsComparisonLineStep(flag > 2000, orginId, targetId, orginList, targetList, uid, level, contentsComparisonKey);
        }).start();
        if (flag > 2000) {
            return R.error("对比结果过多已自动保存，请稍后去对比结果查看");
        } else {
            return R.ok().put("contentsComparisonKey", contentsComparisonKey);
        }
    }

    /**
     * 获取结果
     */
    @RequestMapping("contentsComparison_step")
    @ResponseBody
    public R contentsComparison(@RequestParam("contentsComparisonKey") String contentsComparisonKey) throws IOException {
        redisUtil.saveObject(contentsComparisonKey + "_t", System.currentTimeMillis());
        Object object = redisUtil.getObject(contentsComparisonKey);
        if (null == object) {
            return R.ok().put("data", "正在对比中，请稍后。。。").put("staus", 0);
        } else if (object instanceof Number) {
            return R.ok().put("data", object.toString()).put("staus", 1);
        } else if (object instanceof String) {
            if ("图片切割完成,正在对比中...".equals(object.toString()) || "对比完成,无相似内容".equals(object.toString())) {
                return R.ok().put("data", object.toString()).put("staus", 1);
            } else {
                return R.ok().put("data", JSON.parseArray(convert(JSONArray.parseArray(object.toString())))).put("staus", 5);
            }
        }
        return R.ok().put("data", "对比失败").put("staus", -1);
    }

    /**
     * 机器对比
     *
     * @param type 0 正常分割 1 精细分割
     */
    @RequestMapping("machineComparison")
    @ResponseBody
    public R machineComparison(@RequestParam("rid") Integer rid, @RequestParam("type") Integer type) throws IOException {
//        if (!redisUtil.canWork(userUtil.getUidStr())) {
//            return R.error("应用队列已满，请稍后重试");
//        }
        //所有原图
        List<FileDetails> orginList = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getTpye, 2));

        if (orginList.size() == 0) {
            return R.error("目录下没有文件");
        }

        String contentsComparisonKey = IdUtil.fastSimpleUUID();
        System.out.println("自动化对比_步骤一");
        int loginIdAsInt = userUtil.getUid();
        new Thread(new Runnable() {
            @Override
            public void run() {
                fileDetailService.machineComparisonStep(orginList, loginIdAsInt, rid, type, contentsComparisonKey);
            }
        }).start();

        System.out.println("自动化对比_步骤三");

        return R.ok().put("contentsComparisonKey", contentsComparisonKey);

    }

    /**
     * 机器对比
     */
    @RequestMapping("machineComparison_step")
    @ResponseBody
    public R machineComparisonStep(@RequestParam("rid") Integer rid, @RequestParam("type") Integer type, @RequestParam(value = "ids[]") String[] ids) throws IOException {

//        if (!redisUtil.canWork(userUtil.getUidStr())) {
//            return R.error("应用队列已满，请稍后重试");
//        }
        List<FileDetails> list = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).in(FileDetails::getId, ids).eq(FileDetails::getDeleteFlag, 0));
        list.stream().forEach(f -> {
            f.setVector(featureService.imageFeature(f.getPath()));
            f.setIsWhite(imageComparison.checkWhiteBlock(f.getPath()));
        });
        List<ContentsComparisonRes> comparison = imageComparison.comparisonSort(list, list, userUtil.getUid(), true, null);
        redisUtil.decrement(userUtil.getUidStr());
        return R.ok().put("data", comparison);
    }

    public String convert(JSONArray array) {
        return JSON.toJSONString(array, SerializerFeature.DisableCircularReferenceDetect);
    }

    @RequestMapping("fetchPic")
    @ResponseBody
    public void fetchPic(@RequestParam("picKey") String picKey, HttpServletResponse response) throws IOException {

//        byte[] b1 = requestUtil.fetchlinePath(picKey);
        byte[] b1 = (byte[]) redisUtil.getObject(picKey);
        InputStream in = new ByteArrayInputStream(b1);
        response.setContentType("image/jpg");
        OutputStream out = response.getOutputStream();
        byte[] b2 = new byte[1024];
        int j = 0;
        while ((j = in.read(b2)) != -1) {
            out.write(b2, 0, j);
        }
        out.flush();
        out.close();
        in.close();
    }

    /**
     * 查看全文
     */
    @GetMapping("/getFullText")
    @ResponseBody
    public R getFullText(@RequestParam("id") Integer id, HttpServletRequest request) throws Exception {
        Integer type = 0;
        String pmid = "";
        FileDetails fileDetails = fileDetailService.getById(id);
        FileDetails father = fileDetailService.getById(fileDetails.getFId());

        if (null != fileDetails.getPmid() && fileDetails.getPmid().length() > 10) {
            pmid = fileDetails.getPmid();
        } else {
            if (father.getTpye() != 3 && father.getTpye() != 4 && father.getTpye() != 2) {
                father = fileDetailService.getById(father.getFId());
            }

            pmid = Optional.ofNullable(father.getPmid()).orElse("0");
        }

        if ("0".equals(pmid)) {
            if (father.getTpye() == 3) {
                return R.error("自定义上传无全文");
            }
            String url = minioUtil.getUrl(fileRecordsService.getById(fileDetails.getRid()).getFilePath());
            return R.ok().put("data", url).put("type", 0);
        } else {
            return R.ok().put("data", FullTextUtil.fetchPdfUrl(AesEncryptUtils.decrypt(pmid), type)).put("type", 1);
        }
    }

    /**
     * 重新拆分
     */
    @GetMapping("reSplit")
    @ResponseBody
    public R reSplit(@RequestParam("rid") Integer rid) throws Exception {
        Map<Integer, String> removeMap = new HashMap<>();
        fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getTpye, 2)).stream().forEach(s -> {
            List<FileDetails> list = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, s.getId()));
            for (FileDetails fileDetails : list) {
                removeMap.put(fileDetails.getId(), fileDetails.getPath());
            }
            removeMap.put(s.getId(), s.getPath());

        });
        FileRecord fileRecord = fileRecordsService.getById(rid);
        boolean flag = fileRecordsService.extractFiles(null, rid, userUtil.getUid(), -1, fileRecord.getFilePath(), 1);
        if (!flag) {
            return R.error("重新拆分失败");
        } else {
            for (Integer integer : removeMap.keySet()) {
                minioUtil.remove(removeMap.get(integer));
                fileDetailService.removeById(integer);
            }
            return R.ok();
        }

    }

    /**
     * 整页识别
     */
    @GetMapping("fullPageRecognition")
    @ResponseBody
    public R fullPageRecognition(@RequestParam("rid") Integer rid) throws Exception {
        Map<Integer, String> removeMap = new HashMap<>();
        fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getRid, rid).eq(FileDetails::getTpye, 2)).stream().forEach(s -> {
            List<FileDetails> list = fileDetailService.list(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, s.getId()));
            for (FileDetails fileDetails : list) {
                removeMap.put(fileDetails.getId(), fileDetails.getPath());
            }
            removeMap.put(s.getId(), s.getPath());

        });
        FileRecord fileRecord = fileRecordsService.getById(rid);
        boolean flag = fileRecordsService.extractFiles(null, rid, userUtil.getUid(), -2, fileRecord.getFilePath(), 1);
        if (!flag) {
            return R.error("重新拆分失败");
        } else {
            for (Integer integer : removeMap.keySet()) {
                minioUtil.remove(removeMap.get(integer));
                fileDetailService.removeById(integer);
            }
            return R.ok();
        }

    }

    /**
     * 获取原图
     */
    @GetMapping("/getOrigin")
    @ResponseBody
    public R getOrigin(@RequestParam("id") Integer id) {
        FileDetails fileDetails = fileDetailService.getById(id);

        FileDetails father = fileDetailService.getById(fileDetails.getFId());
        if (father.getTpye() > 2) {
            father = fileDetailService.getById(father.getFId());
        }
        if (fileDetails == null) {
            return R.error("文件不存在");
        }
        return R.ok().put("data", father.setBottomX(fileDetails.getBottomX()).setBottomY(fileDetails.getBottomY()).setTopX(fileDetails.getTopX()).setTopY(fileDetails.getTopY()));
    }

    /**
     * 转移到结果集
     */
    @GetMapping("/movetoresult")
    @ResponseBody
    public R movetoresult(@RequestParam(value = "ids[]") String[] ids, @RequestParam("folderId") Integer folderId) {
        for (String id : ids) {
            FileDetails fileDetails = fileDetailService.getById(id);
            if (fileDetails.getTpye() == 2) {
                byte[] bytes = minioUtil.downloadByte(fileDetails.getPath());
                ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                BufferedImage read = ImgUtil.read(in);
                Integer bottomX = read.getWidth();
                Integer bottomY = read.getHeight();
                fileDetails.setFId(fileDetails.getId());
                fileDetails.setRid(fileDetails.getRid());
                fileDetails.setTpye(4);
                fileDetails.setTopX(0);
                fileDetails.setTopY(0);
                fileDetails.setBottomX(bottomX);
                fileDetails.setBottomY(bottomY);
                fileDetails.setId(null);
            }
            fileDetailService.saveOrUpdate(fileDetails.setCollectionStatus(folderId));
        }
        return R.ok();
    }

    /**
     * 转移到结果集
     */
    @PostMapping("/movetoresult")
    @ResponseBody
    public R movetoresultP(@RequestBody JSONObject req) {
        String[] ids = req.getObject("ids", String[].class);
        Integer folderId = req.getInteger("folderId");
        for (String id : ids) {
            FileDetails fileDetails = fileDetailService.getById(id);
            if (fileDetails.getTpye() == 2) {
                byte[] bytes = minioUtil.downloadByte(fileDetails.getPath());
                ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                BufferedImage read = ImgUtil.read(in);
                Integer bottomX = read.getWidth();
                Integer bottomY = read.getHeight();
                fileDetails.setFId(fileDetails.getId());
                fileDetails.setRid(fileDetails.getRid());
                fileDetails.setTpye(4);
                fileDetails.setTopX(0);
                fileDetails.setTopY(0);
                fileDetails.setBottomX(bottomX);
                fileDetails.setBottomY(bottomY);
                fileDetails.setId(null);
            }
            fileDetailService.saveOrUpdate(fileDetails.setCollectionStatus(folderId));
        }
        return R.ok();
    }

    /**
     * 批量对比
     */
    @GetMapping("/resultmovetoanet")
    @ResponseBody
    public R resultmovetoanet(@RequestParam(value = "ids[]") String[] ids, @RequestParam(value = "topk") Integer topk, @RequestParam(value = "level") Integer level, @RequestParam(value = "source") Integer source, @RequestParam(value = "rid") Integer rid, @RequestParam(value = "rids", required = false) String[] rids) throws Exception {
        if (null == ids || ids.length == 0) {
            throw new RRException("ids不能为空");
        }
        Integer countFlag = 10;
        if (DateUtil.isIn(DateUtil.parse(DateUtil.formatTime(DateUtil.date())), DateUtil.parse("22:00:00"), DateUtil.parse("24:00:00")) || DateUtil.isIn(DateUtil.parse(DateUtil.formatTime(DateUtil.date())), DateUtil.parse("00:00:00"), DateUtil.parse("05:00:00"))) {
            countFlag = 50;
        }
        Long count = new LambdaQueryChainWrapper<>(searchRecordService.getMapper()).eq(SearchRecord::getUId, userUtil.getUid()).eq(SearchRecord::getStatus, 0).count();
//        if (count >= countFlag) {
//            return R.error("应用队列已满，请稍后重试");
//        }

        SearchRecord searchRecord = new SearchRecord().setUId(userUtil.getUid()).setRId(rid).setStatus(0).setLevel(level).setCreateTime(System.currentTimeMillis()).setTodoList(Arrays.stream(ids).map(Integer::parseInt).collect(Collectors.toList())).setTopk(topk).setSource(source).setListId(Arrays.stream(ids).map(Integer::parseInt).collect(Collectors.toList()));
        if (source == 2) {
            searchRecord.setRids(Arrays.stream(rids).map(Integer::parseInt).collect(Collectors.toList()));
        }
        searchRecordService.saveOrUpdate(searchRecord);
        return R.ok();
    }

    /**
     * 记录列表
     *
     * @param vo
     * @return
     */
    @GetMapping("/recordlist")
    @ResponseBody
    public R recordlist(@RequestParam("rid") Integer rid, @RequestParam("type") Integer type) {
        List<SearchRecord> list = searchRecordService.list(Wrappers.<SearchRecord>lambdaQuery().select(SearchRecord::getId, SearchRecord::getRId, SearchRecord::getCreateTime, SearchRecord::getFinishTime, SearchRecord::getStatus, SearchRecord::getLevel, SearchRecord::getTopk, SearchRecord::getSource, SearchRecord::getListId, SearchRecord::getRids, SearchRecord::getReadStatus).eq(SearchRecord::getRId, rid).eq(SearchRecord::getUId, userUtil.getUid()));
        if (type == 0) {
            return R.ok().put("flag", list.stream().anyMatch(r -> r.getReadStatus() == -1));
        } else {
            return R.ok().put("data", list);
        }

    }

    /**
     * 记录列表
     *
     * @param vo
     * @return
     */
    @GetMapping("/read")
    @ResponseBody
    public R read(@RequestParam("id") Integer id) {
        searchRecordService.saveOrUpdate(searchRecordService.getById(id).setReadStatus(1));
        return R.ok().put("data", searchRecordService.getOne(Wrappers.<SearchRecord>lambdaQuery().select(SearchRecord::getJsonResult).eq(SearchRecord::getId, id)));
    }

}
